#include <drivers/pin.h>
#include <rtthread.h>
#include <rtconfig.h>
#include <rtdevice.h>
#include <wiegand.h>
#include <pin.h>

#if defined(RT_USING_ULOG)
	#define LOG_TAG LOG_TAG_WIEGAND
	#define LOG_LVL LOG_LVL_ERROR
	#include <ulog.h>
#else
	#define LOG_I()
	#define LOG_D()
	#define LOG_W()
	#define LOG_E  rt_kprintf
#endif

rt_err_t wiegand_data_check(const rt_uint8_t *data,rt_uint8_t databits,
	rt_uint8_t head,rt_uint8_t tail)
{
	/* head对应偶数个1,tail对应奇数个1 */
	rt_uint8_t i=0,j=0,onebits=0;
	rt_uint8_t tmp;
	rt_uint8_t half;

	RT_ASSERT(RT_NULL!=data);
	half=(databits-2)/2;

	/* 前半部分的数据bit */
	for(i=0;i<half/8;i++)
	{
		tmp=data[i];
		for(j=0;j<8;j++)
		{
			if(tmp&0x80)
			{
				onebits++;
				tmp <<= 1;
			}
		}
	}
	/* 类似26-bit的数据bit分成两半会剩余不足8位的 */
	if(half%8)
	{
		tmp=data[i];
		for(j=0;j<(half%8);j++)
		{
			if(tmp&0x80)
			{
				onebits++;
				tmp <<= 1;
			}
		}
	}
	if((onebits%2)==head)
	{
		return -RT_EIO;
	}
	/* 后半部分的数据bit */
	onebits=0;
	if(half%8)
	{
		tmp=data[i]<<((half%8));
		for(j=(half%8);j<8;j++)
		{
			if(tmp&0x80)
			{
				onebits++;
				tmp <<= 1;
			}
		}
	}
	for(i=0;i<half/8;i++)
	{
		tmp=data[i+half/8];
		for(j=0;j<8;j++)
		{
			if(tmp&0x80)
			{
				onebits++;
				tmp <<= 1;
			}
		}
	}
	if((onebits%2)!=tail)
	{
		return -RT_EIO;
	}
	return RT_EOK;
}

void wiegand_irq_isr(wiegand_package *wiegand)
{
	rt_uint16_t bits,offset;
	rt_uint8_t data;
	
	RT_ASSERT(RT_NULL!=wiegand);

	if(RT_NULL==wiegand->dev.rx_indicate)
	{
		/* 没有设置数据接收函数则直接退出 */
		return;
	}
	data=rt_pin_read(wiegand->data0pin);
	LOG_D("data0=%d",data);
	
	if(wiegand_idle==wiegand->stat)
	{
		wiegand->head=data;
		wiegand->stat=wiegand_receiving;
		rt_memset(wiegand->data,0,wiegand->databits);
		wiegand->index=1;
		rt_timer_start(wiegand->timer);
		return;
	}
	else if(wiegand->index<wiegand->databits)
	{
		bits=(wiegand->databits-1)/8;
		offset=(wiegand->databits-1)%8;
		wiegand->data[bits] <<= 1;
		wiegand->data[bits] |= data;
		wiegand->index++;
	}
	if(wiegand->index>=wiegand->databits)
	{
		rt_timer_stop(wiegand->timer);
		wiegand->tail=data;
		wiegand_data_check(wiegand->data,wiegand->databits,
			wiegand->head,wiegand->tail);
		wiegand->stat=wiegand_idle;
		wiegand->index=0;
		wiegand->dev.rx_indicate(wiegand->data,wiegand->databits/8);
	}
}

void wiegand_timeout(void *para)
{
	wiegand_package *wiegand=(wiegand_package*)para;
	rt_err_t ret;

	RT_ASSERT(RT_NULL!=wiegand);
	if(wiegand_idle==wiegand->stat)
	{
		/*  */
		LOG_D("wiegand(%s) timerout in idle stat",wiegand->dev->parent.name);
		return;
	}
	if(RT_NULL==wiegand->dev.rx_indicate)
	{
		/* 没有设置数据接收函数则直接退出 */
		goto wg_exit;
	}
	if(26>wiegand->index)
	{
		goto wg_exit;
	}
	if((2==(wiegand->index%8)))
	{
		ret=wiegand_data_check(wiegand->data,wiegand->databits,
				wiegand->head,wiegand->tail);
		/*  在接收到全部数据bit之前发生时间中断则也发送数据帧   */	
		if(RT_EOK==ret)
		{
			wiegand->dev.rx_indicate(wiegand->data,wiegand->databits/8);
			goto wg_exit;
		}
		LOG_D("wiegand(%s) data check error",wiegand->dev->parent.name);
	}
wg_exit:
	wiegand->stat=wiegand_idle;
	wiegand->index=0;
	return;
}

#define WIEGAND_BIT_DELAY(bits) (1+5*(bits)*RT_TICK_PER_SECOND/2000)
rt_err_t wiegand_device_init(char *devname,rt_uint16_t bits,rt_base_t data0pin)
{
	wiegand_package *wiegand=RT_NULL;
	rt_device_t dev=RT_NULL;
	rt_uint32_t delay;
	rt_err_t ret;
	
	RT_ASSERT(RT_NULL!=devname);
	if(bits<26 || bits>98)
	{
		LOG_E("error wiegand data bits");
		return -RT_EINVAL;
	}
	/* 先初始化device的数据结构 */
	dev=rt_malloc(sizeof(struct rt_device));
	if(RT_NULL==dev)
	{
		LOG_E("malloc for device wiegand fail");
		return -RT_ENOMEM;
	}
	rt_memset(dev,0,sizeof(struct rt_device));
#ifdef RT_USING_DEVICE_OPS
    dev->ops         = RT_NULL;
#else
    dev->init        = RT_NULL;
    dev->open        = RT_NULL;
    dev->close       = RT_NULL;
    dev->read        = RT_NULL;
    dev->write       = RT_NULL;
    dev->control     = RT_NULL;
#endif
    dev->type        = RT_Device_Class_Miscellaneous;
    dev->rx_indicate = RT_NULL;
    dev->tx_complete = RT_NULL;
    dev->user_data   = RT_NULL;	
	/*  */
	wiegand=rt_malloc(sizeof(wiegand_package));
	if(RT_NULL==wiegand)
	{
		LOG_E("malloc wiegand fail");
		return -RT_ENOMEM;
	}
	rt_memset(wiegand,0,sizeof(wiegand_package));
	delay=WIEGAND_BIT_DELAY(bits);
	wiegand->timer=rt_timer_create(devname,wiegand_timeout,
		wiegand,delay,RT_TIMER_FLAG_ONE_SHOT);
	if(RT_NULL!=wiegand->timer)
	{
		LOG_E("malloc timer fail");
		return -RT_ENOMEM;
	}
	wiegand->data=rt_malloc(bits/8);
	if(RT_NULL!=wiegand->data)
	{
		LOG_E("malloc for data fail");
		return -RT_ENOMEM;
	}
	rt_memset(wiegand->data,0,bits/8);
	wiegand->stat=wiegand_idle;
	wiegand->data0pin=data0pin;
	wiegand->head=0;
	wiegand->tail=0;
	wiegand->index=0;
	wiegand->databits=bits;
	/* 由外部调用函数直接设定数据引脚DATA0的输入方式 */
	//rt_pin_mode(data0pin,PIN_MODE_INPUT);
	dev->user_data=wiegand;
	wiegand->dev=dev;
	ret=rt_device_register(dev,devname,RT_DEVICE_FLAG_RDONLY|RT_DEVICE_FLAG_INT_RX);
	return ret;
}
